# Table of Contents

# 의존성 주입

의존성 주입(Dependency Injection)에 대해 자세히 알아본다.

# 의존성 주입 방법

크게 세 가지 방법으로 의존성을 주입할 수 있다.

# 필드 주입

우선 필드에 빈을 직접 주입할 수 있다.

@Controller
public class MemberController {

    @Autowired
    private MemberService memberService;
}

배열형 멤버변수에 @Autowired를 붙이면 이 배열의 타입과 호환되는 모든 빈을 주입시켜준다.





 


@Controller
public class MemberController {

    @Autowired
    private MemberService[] memberService;
}
public interface MemberService {
    // ...
}
public class MyMemberService implements MemberService {
    // ...
}
public class YourMemberService implements MemberService {
    // ...
}

List형 멤버변수에 @Autowired를 붙이면 이 리스트의 타입과 호환되는 모든 빈을 주입시켜준다.

@Controller
public class MemberController {

    @Autowired
    private List<MemberService> memberService;
}

Map형 멤버변수에 @Autowired를 붙이면 이 리스트의 타입과 호환되는 모든 빈을 주입시켜준다. 이 때 빈의 이름이 Map의 키 값이 된다.

@Controller
public class MemberController {

    @Autowired
    private Map<MemberService> memberService;
}

@Autowired는 필요한 빈을 찾지 못하면 예외를 던진다. 예외를 발생시키지 않으며면 required 속성을 false로 지정하면 된다.

@Controller
public class MemberController {

    @Autowired(required = false)
    private MemberService memberService;   // null 
}

# 생성자 주입

생성자 주입은 스프링에서 가장 권장되는 의존성 주입 방법이다.

@Controller
public class MemberController {

    private MemberService memberService;

    @Autowired
    public MemberController(MemberService memberService) {
        this.memberService = memberService;
    }
}

# Setter 주입

Setter 메소드로도 의존성을 주입할 수 있다.

@Controller
public class MemberController {

    private MemberService memberService;

    @Autowired
    public void setMemberService(MemberService memberService) {
        this.memberService = memberService;
    }
}

# Lombok

Lombok 라이브러리를 사용하는 경우 @RequiredArgsConstructor어노테이션으로 의존성을 주입할 수 있다. 이때 필드는 반드시 final로 설정해야한다.

import lombok.RequiredArgsConstructor;

@Controller
@RequiredArgsConstructor
public class MemberController {

    private final MemberService memberService;
}

# @Autowired

@Autowired타입을 기준으로 빈을 찾아 주입한다. 이 어노테이션은 스프링 프레임워크에 포함되어있다.

import org.springframework.beans.factory.annotation.Autowired;

@Repository
public class PostRepository {

    @Autowired
    private FileManager fileManager;
}

# @Primary

만약 컨테이너에 같은 타입의 빈이 여러 개 존재한다면 의존성 주입이 제대로 되지 않을 수도 있다. 예제를 살펴보자.

@Repository
public class PostRepository {

    @Autowired
    private FileManager fileManager;
}

FileManager는 인터페이스고 여러 구현체들이 빈으로 등록되어있을 수 있다.

public interface FileManager {
    // ..
}
@Component
public class MyFileManager implements FileManager {
    // ..
}
@Component
public class YourFileManager implements FileManager {
    // ..
}

이 경우 @Primary를 사용하면 여러 빈이 주입될 수 있을 때 특정 빈에 우선권을 부여할 수 있다.

import org.springframework.context.annotation.Primary;

@Component
@Primary
public class MyFileManager implements FileManager {
    // ..
}

# @Qualifier

@Qualifier를 사용하여 후보 빈을 명시할 수도 있다. 이 어노테이션은 스프링 프레임워크에 포함되어있다.

import org.springframework.beans.factory.annotation.Qualifier;

@Component
@Qualifier("myFileManager")
public class MyFileManager implements FileManager {
    // ..
}
import org.springframework.beans.factory.annotation.Qualifier;

@Repository
public class PostRepository {

    private FileManager fileManager;

    @Autowired
    public PostRepository(@Qualifier("myFileManager") FileManager fileManager) {
        this.FileManager = fileManager;
    }
}

# @Resource

@Resource는 스프링 프레임워크가 아닌 자바에 포함된 어노테이션으로 이름을 통해 빈을 탐색한다. 스프링 프레임워크의 @Autowired@Qualifier를 합친 것으로 생각하면 된다.

 












import javax.annotation.Resource;

@Repository
public class PostRepository {

    private FileManager fileManager;

    @Resource(name = "myFileManager")
    public PostRepository(FileManager fileManager) {
        this.FileManager = fileManager;
    }
}

# @Inject, @Qualifier

@Inject도 스프링 프레임워크가 아닌 자바에 포함된 어노테이션이다. 이 어노테이션도 @Autowired와 마찬가지로 일단 타입으로 빈을 탐색한다.

import javax.inject.Inject;

@Repository
public class PostRepository {

    private FileManager fileManager;

    @Inject
    public PostRepository(FileManager fileManager) {
        this.FileManager = fileManager;
    }
}

이 어노테이션 역시 타입이 같은 빈이 여러 개일 때 다른 방법을 구사해야한다. 이 때는 @Qualifier를 사옹하여 커스텀 어노테이션을 작성하면 된다.







 

import javax.inject.Qualifier;

@Qualifier
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER})
@Document
@Retention(RetentionPolicy.RUNTIME)
public @interface MyFileManagerAnnotation

 




@Component
@MyFileManagerAnnotation
public class MyFileManager implements FileManager {
    // ..
}








 





import javax.inject.Inject;

@Repository
public class PostRepository {

    private FileManager fileManager;

    @Inject 
    @MyFileManagerAnnotation
    public PostRepository(FileManager fileManager) {
        this.FileManager = fileManager;
    }
}

WARNING

스프링 프레임워크의 org.springframework.beans.factory.annotation.Qualifier가 아니라 Java의 javax.inject.Qualifier를 사용한다는 점에 주의하자.